package com.motu.monstercity.module.common.servermanager;

import com.motu.monstercity.module.common.utility.ServerParam;
import com.motu.vertx.module.utility.base.BaseServerParam;
import com.motu.vertx.module.utility.main.MainService;
import com.motu.vertx.module.utility.mysql.MysqlClient;
import com.motu.vertx.module.utility.mysql.MysqlTool;
import com.motu.vertx.module.utility.toolset.TimeUtils;
import com.motu.vertx.module.utility.toolset.Tool;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Promise;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;


public class ServerManager {
    private static final Logger logger = LoggerFactory.getLogger(ServerManager.class);
    private static ConcurrentHashMap<Integer, ServerInfo> serverList = new ConcurrentHashMap<Integer, ServerInfo>();
    private static ConcurrentHashMap<Integer, ServerGroup> serverGroupMap = new ConcurrentHashMap<>(); // 服务器战区分组配置
    private static ConcurrentHashMap<Integer, JsonArray> warZoneDetail = new ConcurrentHashMap<>(); // 各个战区下的服务器Id列表，key=战区id，value 服务器id列表
    private static ConcurrentHashMap<Integer, JsonArray> actGroupDetail = new ConcurrentHashMap<>(); // 各个战区下的服务器Id列表，key=战区id，value 服务器id列表
    private static JsonArray warZoneList = new JsonArray();//  所有的战区分组id

    public static void init(List<Future> futures) {
        futures.add(initServerList());
        futures.add(initServerGroup());
        futures.add(initServerParams());
    }

    /**
     * 服务器列表（排除合并的服务器）
     */
    public static ConcurrentHashMap<Integer, ServerInfo> getServerList() {
        return getServerList(false, true);// 默认不是gm
    }

    /**
     * 获取服务器列表，如果是gm返回全部，如果不是判断是否服务器已经开服了（排除合并的服务器）
     *
     * @param isGm 是否为gm
     */
    public static ConcurrentHashMap<Integer, ServerInfo> getServerList(boolean isGm) {
        return getServerList(isGm, true);// 默认不是gm
    }

    /**
     * 获取服务器列表，如果是gm返回全部，如果不是判断是否服务器已经开服了
     *
     * @param isGm             是否为gm
     * @param skipMergedServer 是否排除被合并的服务器
     */
    public static ConcurrentHashMap<Integer, ServerInfo> getServerList(boolean isGm, boolean skipMergedServer) {
        long curTime = TimeUtils.getCurTime();
        ConcurrentHashMap<Integer, ServerInfo> list = new ConcurrentHashMap<Integer, ServerInfo>();
        for (ServerInfo server : serverList.values()) {
            if (skipMergedServer && server.isMerged()) {
                continue;// 合服就不用加到服务器列表中
            }
            if (!isGm && curTime < server.getStartTime()) {
                continue;// 不是GM需要判断开服时间
            }
            if (!isGm && server.getStatus() == ServerInfo.SERVER_STATUS_HIDE) {
                continue;// 不是GM需要判断隐藏服
            }
            if (skipMergedServer) {
                list.put(server.getServerId(), server);
            } else {
                list.put(server.getServerId1(), server);
            }
        }
        return list;
    }

    /**
     * 初始化服务器列表
     */
    public static Future<Void> initServerList() {
        Promise promise = Promise.promise();
        String sql = "SELECT * FROM server_info;";
        MysqlTool.queryJsonArrayFromDb(MysqlClient.getServerPool(), sql, new JsonArray(), handler -> {
            if (handler.succeeded()) {
                ConcurrentHashMap<Integer, ServerInfo> tmp = new ConcurrentHashMap<Integer, ServerInfo>();
                ConcurrentHashMap<Integer, JsonArray> actTmp = new ConcurrentHashMap<>();
                JsonArray list = handler.result();
                for (int i = 0; i < list.size(); i++) {
                    ServerInfo info = new ServerInfo(list.getJsonObject(i));
                    tmp.put(info.getServerId1(), info);// 使用合服前的服务器ID
                    logger.info("init server id:" + info.getServerId() + " name:" + info.getServerName() + " status:" + info.getStatus() + " des:" + info.getDes());
                    if (!info.isMerged()) {
                        actTmp.computeIfAbsent(info.getActGroup(), k -> new JsonArray()).add(info.getServerId());
                    }
                }
                serverList.clear();
                serverList = tmp;
                actGroupDetail.clear();
                actGroupDetail = actTmp;
                logger.info("initServerList size:" + serverList.size());
				promise.complete();
            } else {
                logger.error("initServerList " + handler.cause().getMessage());
                promise.fail(handler.cause());
            }
        });
        return promise.future();
    }

    public static ServerInfo getServerInfo(int serverId) {
        ServerInfo serverinfo = serverList.get(serverId);
        if (serverinfo == null) {
            logger.info("getServerInfo error serverid = " + serverId);
        }
        return serverList.get(serverId);
    }

    /**
     * 获取服务器ID
     */
    public static int getServerId(int serverId) {
        int sId = serverId % 1000;
        if (ServerParam.SERVER_ID_DEDUCT > 0) {
            sId = serverId - ServerParam.SERVER_ID_DEDUCT;
        }
        return sId;
    }

    //  获取该服所在的战区分组id
    public static int getWarZoneId(int serverId) {
        ServerGroup serverGroup = getServerGroupMap().get(serverId);
        if (serverGroup == null) {
            return 0;
        } else {
            return serverGroup.getWarZone();
        }
    }

    public static JsonArray  getWarZoneServerList(int serverId) {
        JsonArray reuslt = new JsonArray();
        int warZoneId = getWarZoneId(serverId);
        JsonArray warZoneDetail = getServerIdListByWarZone(warZoneId);
        if (warZoneDetail != null) {
            reuslt = warZoneDetail;
        }
        return reuslt;
    }



    // 获取所有的战区分组id
    public static JsonArray getWarZoneIdList() {
        return warZoneList;
    }

    /**
     * 获取Sxxx格式服务器名称
     */
    public static String getServerNameWithS(int serverId) {
        return "S" + getServerId(serverId);
    }

    /**
     * 服务器ID是否存在，用于部分必定会传未开的服务端ID的功能
     * </p>大部分功能还是需要知道传的serverId是否错误，请使用getServerInfo
     */
    public static boolean isServerIdExist(int serverId) {
        return serverList.containsKey(serverId);
    }

    /**
     * 获取服务器开服天数
     */
    public static int getServerOpenDay(int serverId) {
        ServerInfo serverInfo = getServerInfo(serverId);
        if (serverInfo == null) {
            return 0;
        }
        return TimeUtils.getDiffDay(serverInfo.getStartTime()) + 1;
    }

    /**
     * 获取服务器开服距离某个时间点有几天间隔
     *
     * @param serverId
     * @param time
     * @return
     */
    public static int getServerOpenDiffDay(int serverId, int time) {
        ServerInfo serverInfo = getServerInfo(serverId);
        if (serverInfo == null) {
            return 0;
        }
        if (serverInfo.getStartTime() <= time) {
            return 0;
        }
        // 只需要服务器时间大于指定时间的情况
        return TimeUtils.getDiffDay(serverInfo.getStartTime(), time);
    }

    // 根据战区分组id,获取该战区的所有服务器
    public static JsonArray getServerIdListByWarZone(int warZoneId) {
        if (warZoneDetail.containsKey(warZoneId)) {
            return warZoneDetail.get(warZoneId);
        } else {
            return null;
        }
    }

    public static int getServerActGroup(int serverId) {
        return getServerInfo(serverId).getActGroup();
    }

    public static JsonArray getServerIdListByActGroup(int actGroup) {
        return actGroupDetail.getOrDefault(actGroup, null);
    }


    /**
     * 目标时间，多少天前开的服
     *
     * @return -1服务器不存在或开服时间在目标时间之后，同一天为0
     */
    public static int getServerOpenDayBeforeTime(int serverId, int time) {
        ServerInfo serverInfo = getServerInfo(serverId);
        if (serverInfo == null || serverInfo.getStartTime() > time) {
            return -1;
        }
        return TimeUtils.getDiffDay(serverInfo.getStartTime(), time);
    }

    /***
     * 获取默认服务器
     * @return
     */
    public static ServerInfo getDefaultServer() {
        List<ServerInfo> list = new ArrayList<ServerInfo>();
        ServerInfo defaultServer = null;//最新的服务器
        ServerInfo openServer = null;// 如果取不到默认服，则取已经开服的服务器信息
        for (ServerInfo server : serverList.values()) {
            if (server.getServerStatus() == ServerInfo.SERVER_STATUS_HIDE) {
                continue;
            }
            if (TimeUtils.getCurTime() >= server.getStartTime()) {
                openServer = server;
            }
            if (server.getIsDefault() == 1 && TimeUtils.getCurTime() >= server.getStartTime()) {
                list.add(server);
            }
        }
        if (!list.isEmpty()) {
            if (list.size() > 1) {
                // 有多个默认服时，取最后一个默认服
                list.sort(Comparator.comparing(ServerInfo::getServerId1).reversed());
            }
            defaultServer = list.get(0);
        } else {
            defaultServer = openServer;
        }
        return defaultServer;
    }

    public static Future<Void> initServerParams(){
        Promise<Void> fut = Promise.promise();
        String sql = "SELECT name,value FROM server_params;";
        MysqlTool.queryJsonArrayFromDb(MysqlClient.getServerPool(), sql, new JsonArray(), res->{
            if(res.succeeded()){
                JsonArray list = res.result();
                logger.info("initServerParams size:"+list.size());
                reflectParam(list);
                fut.complete();
            }else{
                logger.error(res.cause().getMessage());
                fut.fail(res.cause());
            }
        });
        return fut.future();
    }

    private static void reflectParam(JsonArray list){
		Class<BaseServerParam> baseClazz = BaseServerParam.class;
		Class<ServerParam> clazz = ServerParam.class;
        for (int i = 0, size = list.size(); i < size; i++) {
            JsonObject obj = list.getJsonObject(i);
            String name = obj.getString("name");
            String value = obj.getString("value");
			Field field = null;
			try {
				// 判断BaseServerParam有没有该字段
				field = baseClazz.getDeclaredField(name);
			} catch (NoSuchFieldException ne) {
				try{
					// 没有则获取ServerParam的字段
					field = clazz.getDeclaredField(name);
				}catch (NoSuchFieldException ne2){
					logger.error("initServerParams error【" + name + "】参数未定义");
				}
			}
			if (field == null) {
				continue;
			}
			try {
				MainService.setServerParamFieldValue(clazz, field, value);
				logger.info("server param name:"+name+" value:"+value);
            } catch (Exception e) {
                logger.error("initServerParams error i = " + i + " name = " + name + " value = " + value);
                if (name.indexOf(' ') != -1) {
                    logger.error(name + "参数名中有空格!!!!");
                }
                if (value.indexOf(' ') != -1) {
                    logger.error(value + "参数数值中有空格!!!!");
                }
            }
        }
    }


    /**
     * 初始化服务器战区分组配置
     */
    public static Future<Void> initServerGroup() {
        String table = "server_group";
        Promise promise = Promise.promise();
        String sql = "select * from " + table + ";";
        MysqlTool.queryJsonArrayFromDb(MysqlClient.getServerPool(), sql, new JsonArray(), res -> {
            if (res.succeeded()) {
                try {
                    ConcurrentHashMap<Integer, ServerGroup> tmp = new ConcurrentHashMap<>();
                    JsonArray result = res.result();
                    JsonArray jsonArray = new JsonArray();// 所有的战区分组id
                    ConcurrentHashMap<Integer, JsonArray> warTmp = new ConcurrentHashMap<>();
                    logger.info("init " + table + " size:" + result.size());
                    for (int i = 0; i < result.size(); i++) {
                        ServerGroup entity = new ServerGroup(result.getJsonObject(i));
                        tmp.put(entity.getServerId(), entity);

                        if (!Tool.isInList(jsonArray, entity.getWarZone())) {
                            jsonArray.add(entity.getWarZone());
                        }
                        warTmp.computeIfAbsent(entity.getWarZone(), k -> new JsonArray()).add(entity.getServerId());
                    }

                    serverGroupMap = tmp;
                    warZoneList = jsonArray;//
                    warZoneDetail = warTmp;
                    promise.complete();
                } catch (Exception e) {
                    logger.error("init " + table + " error exception:" + Tool.getException(e));
                    promise.fail(e);
                }
            } else {
                logger.error(res.cause().getMessage());
                promise.fail(res.cause());
            }
        });
        return promise.future();
    }

    public static ServerGroup getServerGroup(int serverId) {
        ServerGroup result = serverGroupMap.get(serverId);
        if (result == null) {
            logger.error("getServerGroup error key = " + serverId);
        }
        return result;
    }
    public static ConcurrentHashMap<Integer, ServerGroup> getServerGroupMap() { return serverGroupMap; }
}
